package com.shop.cereshop.business.service.shop.impl;

import cn.hutool.core.collection.CollUtil;
import com.shop.cereshop.business.dao.order.CereShopOrderDAO;
import com.shop.cereshop.business.dao.shop.CerePlatformShopDAO;
import com.shop.cereshop.business.page.businessdata.*;
import com.shop.cereshop.business.param.businessdata.OverviewParam;
import com.shop.cereshop.business.service.shop.ShopBusinessDataService;
import com.shop.cereshop.commons.constant.IntegerEnum;
import com.shop.cereshop.commons.enums.OrderStateEnum;
import com.shop.cereshop.commons.enums.PaymentStateEnum;
import com.shop.cereshop.commons.enums.TimeTypeEnum;
import com.shop.cereshop.commons.utils.TimeUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;

import static java.util.stream.Collectors.toMap;

/**
 * @description: 首页二级-经营数据
 * @author zdd
 * @date 2025/9/17 13:21
 * @version 1.0
 */
@Slf4j
@Service
public class ShopBusinessDataServiceImpl implements ShopBusinessDataService {

    @Resource
    private CerePlatformShopDAO cerePlatformShopDAO;
    @Resource
    private CereShopOrderDAO cereShopOrderDAO;

    private static final BigDecimal HUNDRED = new BigDecimal("100");

    @Override
    public OverviewVO overview(OverviewParam param) {

        // 店铺访问次数
        Long visitCount = cerePlatformShopDAO.getVisitByDataType(param.getShopId(), param.getTimeType());
        Long yesterdayVisitCount = cerePlatformShopDAO.getVisitByDataType(param.getShopId(), TimeTypeEnum.YESTERDAY.getCode());

//        Long orderCount = cereShopOrderDAO.getOrderCountByType(param.getShopId(), param.getTimeType(), null);
//        Long yesterdayOrderCount = cereShopOrderDAO.getOrderCountByType(param.getShopId(), TimeTypeEnum.YESTERDAY.getCode(), null);
//        Long completedOrderCount = cereShopOrderDAO.getOrderCountByType(param.getShopId(), param.getTimeType(), OrderStateEnum.COMPLETED.getCode());
//        Long yesterdayCompletedOrderCount = cereShopOrderDAO.getOrderCountByType(param.getShopId(), TimeTypeEnum.YESTERDAY.getCode(), OrderStateEnum.COMPLETED.getCode());

        // 订单统计
        OrderStatisticsDTO statisticsDTO = cereShopOrderDAO.selectOrderStatistics(param.getShopId(), param.getTimeType());

        // 店铺退款金额
        BigDecimal refundAmount = cereShopOrderDAO.getShopReturnAmount(param.getShopId(), param.getTimeType());
        BigDecimal yesterdayRefundAmount = cereShopOrderDAO.getShopReturnAmount(param.getShopId(), TimeTypeEnum.YESTERDAY.getCode());

        OverviewVO overviewVO = new OverviewVO();
        overviewVO.setTypeName(TimeTypeEnum.getMsgByCode(param.getTimeType()));
        overviewVO.setVisitCount(visitCount);
        overviewVO.setYesterdayVisitCount(yesterdayVisitCount);
        BeanUtils.copyProperties(statisticsDTO, overviewVO);
        overviewVO.setDealRate(getConversionRate(statisticsDTO.getOrderCount(), statisticsDTO.getDealOrderCount()));
        overviewVO.setYesterdayDealRate(getConversionRate(statisticsDTO.getYesterdayOrderCount(), statisticsDTO.getYesterdayDealOrderCount()));
        overviewVO.setRefundAmount(refundAmount);
        overviewVO.setYesterdayRefundAmount(yesterdayRefundAmount);
        return overviewVO;
    }

    @Override
    public OrderTrendVO orderTrend(OverviewParam param) {
        List<String> timeLabels = getTimeLabels(param.getTimeType());
        // 指定时间内 按小时、天粒度查询店铺订单数列表
        List<Long> countList = new ArrayList<>();
        List<OrderCountDTO> countDTOList = cereShopOrderDAO.countOrdersByTimeType(param.getShopId(), param.getTimeType());
        if (CollUtil.isNotEmpty(countDTOList)) {
            Map<String, OrderCountDTO> countMap = countDTOList.stream()
                    .filter(dto -> StringUtils.isNotBlank(dto.getTimeLabel()))
                    .collect(toMap(
                            OrderCountDTO::getTimeLabel,
                            Function.identity(),
                            (first, second) -> first
                    ));
            timeLabels.forEach(timeLabel -> {
                if (StringUtils.isNotBlank(timeLabel)) {
                    OrderCountDTO dto = countMap.get(timeLabel);
                    countList.add(dto != null ? dto.getCount() : 0L);
                } else {
                    countList.add(0L);
                }
            });
        } else {
            countList.addAll(Collections.nCopies(timeLabels.size(), 0L));
        }

        // 指定时间内 查询店铺订单数
        OrderCompareCountDTO compareCountDTO = cereShopOrderDAO.getOrderCountByTimeType(param.getShopId(), param.getTimeType());
        Long orderCount = Optional.ofNullable(compareCountDTO)
                .map(OrderCompareCountDTO::getCount)
                .orElse(0L);
        Long compareOrderCount = Optional.ofNullable(compareCountDTO)
                .map(OrderCompareCountDTO::getCompareCount)
                .orElse(0L);

        OrderTrendVO orderTrendVO = new OrderTrendVO();
        orderTrendVO.setTypeName(TimeTypeEnum.getMsgByCode(param.getTimeType()));
        orderTrendVO.setOrderCount(orderCount);
        orderTrendVO.setCompareOrderCount(compareOrderCount);
        orderTrendVO.setTimes(timeLabels);
        orderTrendVO.setCounts(countList);
        return orderTrendVO;
    }

    @Override
    public PendingPayOrderVO pendingOrderData(OverviewParam param) {
        // 查询待待款订单数、待付款金额、待到账金额
        Integer paymentState = PaymentStateEnum.UNPAID.getCode();
        PendingPayOrderDTO dto = cereShopOrderDAO.getPendingPayOrderByTimeType(param.getShopId(), param.getTimeType(), paymentState);

        PendingPayOrderVO orderDataVO = new PendingPayOrderVO();
        BeanUtils.copyProperties(dto, orderDataVO);
        orderDataVO.setTypeName(TimeTypeEnum.getMsgByCode(param.getTimeType()));
        return orderDataVO;
    }

    @Override
    public OldCustomerDataVO oldCustomerData(OverviewParam param) {
        OldCustomerDataVO vo = new OldCustomerDataVO();
        vo.setTypeName(TimeTypeEnum.getMsgByCode(param.getTimeType()));

        // todo 测试数据，后续需要从数据库中获取数据
        if (TimeTypeEnum.TODAY.getCode().equals(param.getTimeType())) {
            vo.setRate("7.05%");
            vo.setCompareRate("6.95%");
            vo.setVisitRate("8.36%");
            vo.setCompareVisitRate("8.21%");
            vo.setFansCount(8L);
            vo.setAddedFansCount(2L);
        }
        if (TimeTypeEnum.YESTERDAY.getCode().equals(param.getTimeType())) {
            vo.setRate("6.21%");
            vo.setCompareRate("6.03%");
            vo.setVisitRate("7.47%");
            vo.setCompareVisitRate("7.68%");
            vo.setFansCount(7L);
            vo.setAddedFansCount(1L);
        }
        if (TimeTypeEnum.NEARLY_7_DAYS.getCode().equals(param.getTimeType())) {
            vo.setRate("5.98%");
            vo.setCompareRate("5.79%");
            vo.setVisitRate("7.16%");
            vo.setCompareVisitRate("7.33%");
            vo.setFansCount(31L);
            vo.setAddedFansCount(5L);
        }
        if (TimeTypeEnum.NEARLY_30_DAYS.getCode().equals(param.getTimeType())) {
            vo.setRate("5.75%");
            vo.setCompareRate("5.56%");
            vo.setVisitRate("6.92%");
            vo.setCompareVisitRate("7.11%");
            vo.setFansCount(122L);
            vo.setAddedFansCount(12L);
        }
        return vo;
    }

    /**
     * 获取订单转化率
     * @param count 订单总数
     * @param paidCount 已支付订单数
     * @return 订单转化率
     */
    private static BigDecimal getConversionRate(Long count, Long paidCount) {
        if (count == null || count.compareTo(0L) <= 0) {
            return BigDecimal.ZERO;
        }
        if (paidCount == null || paidCount.compareTo(0L) <= 0) {
            return BigDecimal.ZERO;
        }
        return BigDecimal.valueOf(paidCount).multiply(HUNDRED).divide(BigDecimal.valueOf(count), 0, RoundingMode.HALF_UP);
    }

    /**
     * 获取时间标签列表
     * @param timeType 时间粒度
     * @return 时间标签
     */
    private List<String> getTimeLabels(Integer timeType) {
        List<String> times = new ArrayList<>();
        if (IntegerEnum.CONDITION_TODAY.getCode().equals(timeType) || IntegerEnum.CONDITION_YESTERDAY.getCode().equals(timeType)) {
            for (int i = 0; i < 23; i++) {
                String time = i + ":00";
                times.add(time);
            }
        } else if (IntegerEnum.CONDITION_WEEK.getCode().equals(timeType)) {
            times = TimeUtils.getLastNDays(7, true);
        } else if (IntegerEnum.CONDITION_THIRD.getCode().equals(timeType)) {
            times = TimeUtils.getLastNDays(30, true);
        }
        return times;
    }

}
